/*
 *  Scripts incluídos antes deste:
 *      - API do Google Maps;
 *      - jquery.js;
 *      - jquery.maskedinput.js
 *      - bootstrap.js
 */

/* =========================================================================
 * Variáveis globais. Não altere o nome de nenhuma delas sem checar os
 * demais arquivos de scripts, pois algumas delas são referenciadas
 * externamente.
 * ========================================================================= */
// Coordenadas iniciais em São Carlos.
var _myCenter = new google.maps.LatLng(-22.008631, -47.892838);

// Objetos de serviços do Google.
var _map;               // Mapa.
var _geocoder;          // Geocoder (conversões coordenada-endereço).
var _directionsService; // Directions (calcula rotas).
var _directionsDisplay; // Directions Renderer (desenha rotas).

// Marcador do local selecionado pelo usuário.
var _userMarker;
// Demais marcadores em exibição no mapa.
var _markersArray = [];

// Info window que aparece ao interagir com um marcador.
var _infoWindow;
// Array de conteúdos das info windows dos estabelecimentos.
// As chaves desse array serão os IDs dos estabelecimentos.
var _infoWindowContents = [];

// Ícones pré-definidos.
// Importante: siga esse padrão de nomeação dos atributos.
var _icons = {
    generic: '/img/restaurant.png',
    types: {
        restaurante: '/img/restaurant_buffet.png',
        pizzaria: '/img/pizzaria.png',
        // pastelaria: '',
        lanchonete: '/img/sandwich-2.png',
        churrascaria: '/img/barbecue.png',
        bar: '/img/bar.png',
        padaria: '/img/restaurant_breakfast.png',
        // doceria: '',
        sorveteria: '/img/icecream.png'
    },
    specialties: {
        // massas: '',
        vegetariano: '/img/restaurant_vegetarian.png',
        peixes: '/img/restaurant_fish.png',
        // rodizio: '',
        pratos_finos: '/img/gourmet_0star.png',
        // por_quilo: '',
        fast_food: '/img/fastfood.png',
        // comida_caseira: '',
        comida_chinesa: '/img/restaurant_chinese.png',
        comida_japonesa: '/img/japanese-food.png',
        comida_mexicana: '/img/restaurant_mexican.png',
        comida_francesa: '',
        comida_italiana: '/img/restaurant_italian.png',
        comida_indiana: '/img/restaurant_indian.png',
        // comida_espanhola: '',
        // salgados: '',
        // frituras: '',
        // doces: ''
    }
};

/* =========================================================================
 * Função que inicializa o mapa e seus atributos.
 * ========================================================================= */
function initialize() {
    // Define as opções de inicialização do mapa.
    var mapProp = {
        center: _myCenter,       // Posição central.
        zoom: 14,                // Zoom inicial.
        disableDefaultUI: false, // Desabilita interfaces de usuário.
        panControl: true,        // Interface de controle de translação.
        zoomControl: true,       // Interface de controle de zoom.
        mapTypeControl: true,    // Interface de controle de tipo de mapa.
        scaleControl: true,      // Interface de controle de escala.
        streetViewControl: true, // Interface do Google Street View.
        overviewMapControl: true,// Interface de controle de overview.
        rotateControl: true,     // Interface de controle de rotação.
        mapTypeId: google.maps.MapTypeId.ROADMAP // Tipo de mapa.
    };

    // Instancia o mapa e os objetos de serviços do Google Maps.
    _map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
    _infoWindow = new google.maps.InfoWindow();
    _geocoder = new google.maps.Geocoder();
    _directionsService = new google.maps.DirectionsService();
    _directionsDisplay = new google.maps.DirectionsRenderer({draggable: true});
    _directionsDisplay.setMap(_map);

    // Instancia e configura o autocomplete no campo de endereço.
    var addressInput = document.getElementById("addressInput");
    var autocompleteOptions = {
        types: ['establishment', 'geocode']
    };
    var autocomplete = new google.maps.places.Autocomplete(addressInput, autocompleteOptions);
    
    // Evento para tratar um "clique" do usuário no mapa.
    google.maps.event.addListener(_map, 'click', function(event) {
        placeMarker(event.latLng, null, true);
    });

    // Evento de mudança de opção selecionada no autocomplete.
    google.maps.event.addListener(autocomplete, 'place_changed', function() {
        var place = autocomplete.getPlace();
        placeMarker(place.geometry.location, null, true);
    });

    // Evento de clique no botão "Marcar Ponto".
    $('#markButton').click(function(e) {
        placeMarkerByAddress();
    });

    // Checa se existe um objeto de preferências pré-definidas de usuário.
    // Existindo, manda colocar um marcador na sua localização padrão.
    if (typeof _prefsUsuario !== 'undefined') {
        placeMarker(_prefsUsuario.geolocalizacao, null, true);
    }
}

/* =========================================================================
 * Função que adiciona no mapa um marcador, dada a sua localização e,
 * opcionalmente, o seu ícone e a opção de remover marcadores anteriores.
 * ========================================================================= */
function placeMarker(location, icon, deletePreviousMarkers) {
    var lat = location.lat();
    var lng = location.lng();

    // Só será interessante remover os marcadores quando estivermos em
    // uma situação que NÃO é uma pesquisa de estabelecimentos.
    // Neste caso, o marcador a ser colocado é um marcador de usuário.
    if (deletePreviousMarkers) {
        // Centraliza o mapa na região das coordenadas.
        _map.setCenter(location);
        
        // Remove o marcador do usuário, se houver algum.
        if (typeof _userMarker !== "undefined") {
            _userMarker.setMap(null);
        }
        // (Re)cria o marcador do usuário.
        _userMarker = new google.maps.Marker({
            animation: google.maps.Animation.DROP,
            position: location,
            draggable: true,
            map: _map
        });

        // (Re)define os tratadores de eventos para esse marcador.
        google.maps.event.clearInstanceListeners(_userMarker);
        google.maps.event.addListener(_userMarker, 'click', function() {
            _infoWindow.setContent('<h5>Você está em:</h5>Latitude = ' + lat +
                                   '<br/>Longitude = ' + lng + '</p>');
            _infoWindow.open(_map, this);
        });

        // Passa os valores de latitude e longitude para as
        // respectivas variáveis do formulário.
        $("#latitude").val(lat);
        $("#longitude").val(lng);
        $("#addressInput").val("");
        
        if (window.location.pathname == '/pontosGastronomicos/cadastrar.jsp' || window.location.pathname == '/usuarios/cadastrar.jsp') {
            pontoSelecionado();
        }        
    }
    // Neste caso, estamos inserindo marcadores para os resultados
    // de uma pesquisa.
    else {
        var searchMarker;

        // Define a imagem do ícone e sua sombra.
        // Tendo sido fornecido um endereço de imagem de ícone, usa-a.
        if (icon !== null) {
            var image = new google.maps.MarkerImage(icon,
                new google.maps.Size(32.0, 37.0),
                new google.maps.Point(0, 0),
                new google.maps.Point(16.0, 18.0)
            );
            var shadow = new google.maps.MarkerImage('/img/shadow.png',
                new google.maps.Size(51.0, 37.0),
                new google.maps.Point(0, 0),
                new google.maps.Point(16.0, 18.0)
            );

            // Coloca o marcador usando o ícone personalizado.
            searchMarker = new google.maps.Marker({
                animation: google.maps.Animation.DROP,
                position: location,
                map: _map,
                icon: image,
                shadow: shadow
            });
        }
        // Senão, coloca o marcador usando o ícone padrão.
        else {
            searchMarker = new google.maps.Marker({
                animation: google.maps.Animation.DROP,
                position: location,
                draggable: true,
                map: _map,
            });
        }

        // Adiciona o marcador no array.
        _markersArray.push(searchMarker);
        // Retorna o marcador criado.
        return searchMarker;
    }
}

/* =========================================================================
 * Função que determina usa o geocoder para determinar a localização e
 * colocar um marcador no mapa a partir do seu endereço.
 * ========================================================================= */
function placeMarkerByAddress() {
    // Pega o endereço que o usuário digitou.
    var address = document.getElementById('addressInput').value;

    // Se houver algum endereço.
    if (address) {
        // Usa o geocoder para converter o endereço em coordenadas.
        _geocoder.geocode({'address': address},
            function(results, status) {
                // Em caso de sucesso.
                if (status == google.maps.GeocoderStatus.OK) {
                    // Manda adicionar o marcador.
                    placeMarker(results[0].geometry.location, null, true);
                    // Passa os valores de latitude e longitude para as
                    // respectivas variáveis do formulário.
                    $("#latitude").val(results[0].geometry.location.lat());
                    $("#longitude").val(results[0].geometry.location.lng());
                }
                // Em caso de falha, mostra a mensagem de erro.
                else {
                    alert('Geocoder falhou por causa de: ' + status);
                }
        });
    }
    // Caso contrário, não há o que fazer.
    else {
        alert('Nenhum endereço digitado!');
    }
}

/* =========================================================================
 * Função que apaga todos os marcadores (exceto o de usuário) do mapa.
 * ========================================================================= */
function deleteOverlay() {
    for (var i = 0; i < _markersArray.length; i++) {
        _markersArray[i].setMap(null);
    }
    _markersArray = [];
    _directionsDisplay.setMap(null);
}


/* =========================================================================
 * Função que cria o conteúdo de uma info window a partir dos dados de
 * um estabelecimento.
 * ========================================================================= */
function createInfoWindowContent(place, marker) {
    // Cabeçalho com o nome do estabelecimento.
    var header = '<h4>' + place.nome + '</h4>';

    // HTML da criação das tabs.
    var tabsBegin = '<div class="tabbable">\
                        <ul class="nav nav-tabs">\
                            <li class="active">\
                               <a href="#infoTab1" data-toggle="tab">Informações</a>\
                            </li>';
    // A aba 2 só é visível na página principal.
    if (window.location.pathname == '/' ||
        window.location.pathname == '/index.jsp') {
        tabsBegin += '      <li>\
                               <a href="#infoTab2" data-toggle="tab">Opções</a>\
                            </li>';
    }
    tabsBegin += '      </ul>\
                        <div id="infoWindowTab" class="tab-content">';
    
    var preco = place.precoMedio.toString().split('.');
    var intPart = preco[0];
    var decPart = (preco.length > 1 ? preco[1] : '');
    decPart = (decPart + '00').substr(0,2);
    place.precoMedio = intPart + ',' + decPart;   
    
    // HTML da tab com as informações do estabelecimento.
    var tab1 = '<div class="tab-pane active" id="infoTab1">\
                    <strong>Tipo: </strong>' + place.tipo + '<br/>\
                    <strong>Especialidades: </strong>' + place.estilos.join(', ') + '<br/>\
                    <strong>Telefone</strong>: ' + (place.telefone?place.telefone:"") + '<br/>\
                    <strong>Website/e-mail</strong>: <a href="' + (place.email?place.email:"") + '">' +
                        (place.email?place.email:"") + '</a><br/>\
                    <strong>Abre às</strong>: ' + (place.horaAbre?place.horaAbre:"") + '<br/>\
                    <strong>Fecha às</strong>: ' + (place.horaFecha?place.horaFecha:"") + '<br/>\
                    <strong>Descrição/cardápio</strong>: ' + (place.descricao?place.descricao:"") + '<br/>\
                    <strong>Preço médio</strong>: R$ ' + place.precoMedio + '<br/>\
                    <strong>Avaliação média</strong>: ' + place.avaliacaoMedia + '/10<br/>\
                    <strong>Quantidade de Avaliações</strong>: ' + place.quantidadeAvaliacoes + '<br/>\
                    <strong>Cadastrado por</strong>: ' + (place.quemCadastrou.nome?place.quemCadastrou.nome:"USUÁRIO DELETADO DO SISTEMA") + '<br/>\
                </div>';

    // HTML da tab com as opções de cálculo de rota e atualizações.
    // A primeira parte (rota) é visível a todos os usuários na página
    // principal, mas não nas demais.
    var tab2 = '';
    if (window.location.pathname == '/' ||
        window.location.pathname == '/index.jsp') {
        tab2 = '<div class="tab-pane" id="infoTab2">\
                        <form class="form-horizontal">\
                            <fieldset>\
                                <div class="control-group">\
                                    <label class="control-label">Como chegar:</label>\
                                    <div class="controls">\
                                        <a id="calcRouteLink" href="#">Me mostre o caminho</a>\
                                    </div>\
                                </div>';
        
        // A parte a seguir (avaliação e preço) são visíveis apenas aos
        // usuários que estiverem logados, e somente na página principal.
        // Sabemos que o usuário está logado se existir um objeto com
        // as suas preferências definido.
        if (typeof _prefsUsuario !== 'undefined') {
            tab2 += '           <div class="control-group">\
                                    <label class="control-label">Minha avaliação:</label>\
                                    <div class="controls">\
                                        <input id="ratingInput" type="number" min="0" max="10" class="span6"/>\
                                        /10\
                                    </div>\
                                </div>\
                                <div class="control-group">\
                                    <label class="control-label">Quanto gastei:</label>\
                                    <div class="controls">\
                                        <input id="expenditureInput" type="number" min="0" class="span6"/>\
                                        ,00\
                                    </div>\
                                </div>\
                                <button id="saveButton" type="button" class="btn btn-primary">\
                                    <i class="icon-check icon-white"></i>\
                                    Salvar e fechar\
                                </button>';
        }
        // Fechando as tags.
        tab2 += '           </fieldset>\
                        </form>\
                    </div>';
    }

    // HTML para fechar as tags restantes.
    var tabsEnd = '</div></div>';

    // Define, enfim, o conteúdo da info window para o estabelecimento.
    var content = header + tabsBegin + tab1 + tab2 + tabsEnd;
    _infoWindowContents[place.id] = content;

    // Tratador dos eventos de clique no marcador.
    // Mostra as informações do estabelecimento correspondente.
    google.maps.event.clearInstanceListeners(marker);
    google.maps.event.addListener(marker, 'click', function() {
        _infoWindow.setContent(_infoWindowContents[place.id]);
        _infoWindow.open(_map, this);

        // O código abaixo só executa quando a info window está
        // completamente carregada.
        google.maps.event.addListenerOnce(_infoWindow, 'domready', function() {
            var calcRouteLink = $('#calcRouteLink');
            var saveButton = $('#saveButton');

            // Evento de clique no link "Me mostre o caminho".
            calcRouteLink.off('click');
            calcRouteLink.click(function(e) {
                // Manda calcular e fecha a info window.
                e.preventDefault();
                calculateRoute(_userMarker.getPosition(), marker.getPosition());
                _infoWindow.close();
            });

            // Evento de clique no botão "Salvar e fechar".
            saveButton.off('click');
            saveButton.click(function(e) {
                // Pega os dados a serem salvos.
                e.preventDefault();
                var rating = $('#ratingInput').val();
                var expenditure = $('#expenditureInput').val();
                // Se ambos tiverem sido fornecidos, manda salvar e
                // fecha a info window.
                if (rating && expenditure) {
                    updateRequest(place.id, rating, expenditure);
                    _infoWindow.close();
                }
                // Caso contrário, nada a fazer.
                else {
                    alert('Insira os valores primeiro!');
                }
            });
        });

    });
}

/* =========================================================================
 * Função que calcula uma rota, dados os pontos de origem e destino.
 * ========================================================================= */
function calculateRoute(origin, destination) {
    // Define os parâmetros da requisição.
    var request = {
        origin: origin,
        destination: destination,
        travelMode: google.maps.TravelMode.DRIVING
    };

    // Usa o directions para calcular a rota até o destino.
    _directionsService.route(request, function(result, status) {
        // Em caso de sucesso.
        if (status == google.maps.DirectionsStatus.OK) {
            // Manda desenhar e escrever as instruções da rota.
            var panel = document.getElementById('directionsPanel');
            _directionsDisplay.setMap(_map);
            _directionsDisplay.setDirections(result);
            _directionsDisplay.setPanel(panel);
        }
        // Em caso de falha, mostra o erro.
        else {
            alert('Falha do Google Directions: ' + status);
        }
    });
}

/* =========================================================================
 * Função que faz uma requisição assíncrona (Ajax) para atualização de
 * avaliação e gastos de um dado estabelecimento.
 * ========================================================================= */
function updateRequest(placeId, rating, expenditure) {
    // Obtém os parâmetros da requisição.
    var url = "/ajax/updateRatingAndExpenditure.jsp";
    var dataObj = {
        idPonto: placeId,
        avaliacao: rating,
        gastos: expenditure
    };

    // Faz a requisição passando os parâmetros e as funções callback.
    $.ajax(url, {
        crossDomain: true,
        type       : 'POST',
        encoding   : 'ISO-8859-1',
        data       : dataObj
    }).done(function(data, textStatus) {
        updateResponse(data, textStatus);
    }).fail(function(data, textStatus) {
        var message = "ERRO: Não foi possível processar a requisição.";
        updateFeedback(-1, message);
    });
}

/* =========================================================================
 * Função callback que executa quando a requisição assíncrona é
 * bem-sucedida.
 * ========================================================================= */
function updateResponse(data, textStatus) {
    // alert(data);
    var obj = JSON.parse(data.trim());
    updateFeedback(obj.stat, obj.message);
}

/* =========================================================================
 * Função que exibe as mensagens ao usuário conforme a resposta recebida
 * pela requisição assíncrona.
 * ========================================================================= */
function updateFeedback(stat, message) {
    var responseDiv = $('#responseDiv').empty();

    if (stat > 0) {
        var html = '<div class="alert alert-success">\
                    <button type="button" class="close" data-dismiss="alert">&times;</button>\
                    <span class="label label-success"><i class="icon-ok icon-white"></i></span> ' +
                    message + '</div>';
        responseDiv.fadeIn(500).delay(5000).fadeOut(500);
        responseDiv.append(html);
    } else {
        var html = '<div class="alert alert-error">\
                    <button type="button" class="close" data-dismiss="alert">&times;</button>\
                    <span class="label label-important"><i class="icon-remove icon-white"></i></span> '
                    + message + '</div>';
        responseDiv.fadeIn(500).delay(5000).fadeOut(500);
        responseDiv.append(html);
    }
}

// Inicializa quando o documento estiver completamente carregado.
google.maps.event.addDomListener(window, 'load', initialize);
